package top.lingkang.finalgateway.admin.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.MethodType;
import top.lingkang.finalgateway.FinalGateway;
import top.lingkang.finalgateway.admin.constants.CommonValue;
import top.lingkang.finalgateway.admin.constants.LogType;
import top.lingkang.finalgateway.admin.constants.StatusCode;
import top.lingkang.finalgateway.admin.dto.ResponseResult;
import top.lingkang.finalgateway.admin.dto.ResponseResultPage;
import top.lingkang.finalgateway.admin.entity.ConfigHistoryEntity;
import top.lingkang.finalgateway.admin.mapper.ActionLogMapper;
import top.lingkang.finalgateway.admin.mapper.ConfigHistoryMapper;
import top.lingkang.finalgateway.admin.mapper.ConfigMapper;
import top.lingkang.finalgateway.admin.param.HistorySearchParam;
import top.lingkang.finalgateway.admin.vo.ConfigHistoryVO;
import top.lingkang.finalgateway.config.GatewayConfig;
import top.lingkang.finalgateway.config.RouterConfig;
import top.lingkang.finalgateway.utils.CommonUtils;
import top.lingkang.finalgateway.utils.ConfigUtils;
import top.lingkang.mm.page.PageHelper;
import top.lingkang.mm.page.PageInfo;
import top.lingkang.mm.solon.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @author lingkang
 * @create by 2024/5/14 17:25
 */
@Slf4j
@Controller
@Mapping("/api/config")
public class ConfigController {
    @Inject
    private ConfigHistoryMapper configHistoryMapper;
    @Inject
    private ActionLogMapper actionLogMapper;
    @Inject
    private ConfigMapper configMapper;

    @Mapping(value = "/get", method = MethodType.GET)
    public Object get() {
        return new ResponseResult<>().setData(FinalGateway.config.getXml());
    }

    @Transactional
    @Mapping(value = "/set", method = MethodType.POST)
    public Object set(String xml, String type, String remark) {
        Assert.notBlank(xml, "配置内容不能为空");
        Assert.notBlank(remark, "备注不能为空");
        Assert.isTrue(remark.length() <= 125, "备注长度不能超过 125 个字符");
        // 检查格式
        String check = ConfigUtils.xmlCheck(xml);
        if (check != null)
            return new ResponseResult<>().fail("配置格式有误：" + check);
        String old = configHistoryMapper.lastXML();
        if (xml.equals(old))
            return new ResponseResult<>().ok("配置无变化");
        GatewayConfig o = FinalGateway.config;
        try {
            GatewayConfig config = ConfigUtils.loadXML(xml);
            configMapper.updateDataById("xml", xml, new Date());
            FinalGateway.config = config;
            FinalGateway.restartAllService();
            configHistoryMapper.add(xml, type == null ? CommonValue.history_update : type, o.getXml(), remark);
            actionLogMapper.addLog(LogType.config_update_success, xml);
        } catch (Exception e) {
            log.error("配置格式有误", e);
            FinalGateway.config = o;
            actionLogMapper.addLog(LogType.config_update_fail, e.getMessage());
            return new ResponseResult<>().fail(StatusCode.ALERT, "配置格式有误: " + e.getMessage());
        }
        return new ResponseResult<>().ok();
    }

    @Mapping(value = "/back", method = MethodType.POST)
    public Object back(String id, String type, String remark) {
        Assert.notBlank(id, "id 不能为空");
        Assert.notBlank(type, "type 不能为空");

        if ("left".equals(type)) {
            String lastId = configHistoryMapper.lastId();
            if (id.equals(lastId))
                return new ResponseResult<>().fail("已经是当前版本了");
        }

        ConfigHistoryEntity entity = configHistoryMapper.selectById(id);
        Assert.notNull(entity, "配置不存在");

        if ("left".equals(type)) {
            return set(entity.getXml(), CommonValue.history_back, remark);
        } else if ("right".equals(type)) {
            return set(entity.getOld(), CommonValue.history_back, remark);
        } else
            return new ResponseResult<>().fail("不支持的类型: " + type);
    }

    @Mapping(value = "/history", method = MethodType.GET)
    public Object history(HistorySearchParam param) {
        PageHelper.startPage(param.getPage(), param.getSize());
        List<ConfigHistoryVO> list = configHistoryMapper.list(param);
        PageInfo page = PageHelper.getPage();
        return new ResponseResultPage<>().setData(list)
                .setPage(param.getPage())
                .setSize(param.getSize())
                .setTotal(page.getTotal());
    }

    @Mapping(value = "/router", method = MethodType.GET)
    public Object router() {
        return new ResponseResult<>().setData(FinalGateway.config);
    }

    @Mapping(value = "/sample", method = MethodType.GET)
    public void sample(Context context) {
        String sample = IoUtil.readUtf8(getClass().getClassLoader().getResourceAsStream("config-sample.xml"));
        context.headerSet("Content-Type", "application/xml");
        context.output(sample);
    }

    @Mapping(value = "/historyDetail", method = MethodType.GET)
    public Object historyDetail(String id) {
        Assert.notBlank(id, "id 不能为空");
        ConfigHistoryEntity entity = configHistoryMapper.selectById(id);
        Assert.notNull(entity, "配置不存在");
        return new ResponseResult<>().ok(entity);
    }

}
